﻿// Copyrights (c) 2017 GlassGrass

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GlassGrass.Unity.GuiFramework
	{


	/// <summary> Value converter. </summary>
	/// <typeparam name="TValue"></typeparam>
	/// <typeparam name="TDisplay"></typeparam>
	public interface IValueConverter<TValue, TDisplay>
		{

		/// <summary></summary>
		/// <param name="value"></param>
		/// <returns></returns>
		TDisplay Format(TValue value);

		/// <summary></summary>
		/// <param name="expression"></param>
		/// <returns></returns>
		Optional<TValue> Parse(TDisplay expression);

		/// <summary></summary>
		/// <param name="lhs"></param>
		/// <param name="rhs"></param>
		/// <returns></returns>
		bool Equals(TValue lhs, TValue rhs);

		}



	/// <summary> IValueConverter implement. </summary>
	/// <typeparam name="TValue"></typeparam>
	/// <typeparam name="TDisplay"></typeparam>
	public class ValueConverter<TValue, TDisplay> : IValueConverter<TValue, TDisplay>
		{

		private readonly Func<TValue, TDisplay> _format;

		private readonly Func<TDisplay, Optional<TValue>> _parse;

		private readonly Func<TValue, TValue, bool> _equals;



		/// <summary></summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public TDisplay Format(TValue value)
			=> _format( value );



		/// <summary></summary>
		/// <param name="expression"></param>
		/// <returns></returns>
		public Optional<TValue> Parse(TDisplay expression)
			=> _parse( expression );



		/// <summary></summary>
		/// <param name="lhs"></param>
		/// <param name="rhs"></param>
		/// <returns></returns>
		public bool Equals(TValue lhs, TValue rhs)
			=> _equals( lhs, rhs );



		/// <summary> Create ValueConverter instance. </summary>
		/// <param name="format"></param>
		/// <param name="parse"></param>
		/// <param name="equals"></param>
		public ValueConverter(
			Func<TValue, TDisplay> format,
			Func<TDisplay, Optional<TValue>> parse,
			Func<TValue, TValue, bool> equals)
			{
			_format = format;
			_parse = parse;
			_equals = equals;
			}



		/// <summary> Get default converter. </summary>
		/// <returns></returns>
		public static ValueConverter<TValue, TDisplay> GetDefaultConverter()
			{
			if (typeof(TValue) == typeof(TDisplay))
				{
				return new ValueConverter<TValue, TValue>(
					v => v,
					d => d,
					(l, r) => object.Equals(l, r))
					as ValueConverter<TValue, TDisplay>;
				}

			if( IsImplimantationOf( typeof( TValue ),typeof( IConvertible )) 
				&& IsImplimantationOf( typeof( TDisplay ), typeof( IConvertible )) )
				{
				return new ValueConverter<TValue, TDisplay>(
					v => (TDisplay) Convert.ChangeType(v, typeof(TDisplay)),
					d => (TValue) Convert.ChangeType(d, typeof(TValue)),
					(l, r) => object.Equals(l, r));
				}

			throw new NotSupportedException();
			}


		private static bool IsImplimantationOf(Type targetType, Type interfaceType)
			=> targetType.GetInterfaces().Any(type => type == interfaceType);

		}

	}
